package redis

import (
	"errors"
	"github.com/go-redis/redis"
	"math"
	"time"
)

/* 投票的几种情况分析：
direction=1时，有两种情况：
	1、之前没有投过票，现在投赞成票  	--》 更新分数和投票记录	差值的绝对值是：1	+432
	2、之前投反对票，现在投赞成票		--》 更新分数和投票记录	差值的绝对值是：2	+432*2
direction=0时：
	1、之前投反对票，现在取消投票		--》 更新分数和投票记录	差值的绝对值是：1	+432
	2、之前投赞成票，现在取消投票		--》 更新分数和投票记录	差值的绝对值是：1	-432
direction=-1时
	1、之前没有投过票，现在投反对票		--》 更新分数和投票记录	差值的绝对值是：1	-432
	2、之前投赞成票，现在投反对票		--》 更新分数和投票记录	差值的绝对值是：2	-432*2

投票的限制
每个帖子自发表之日起一个星期之内允许用户投票，超过一个星期就不允许再投票了。
	1、到期之后将redis中保存的赞成票和反对票数存储到mysql表中
	2、到期之后删除那个 KeyPostVotedZSetPF
*/
const (
	oneWeekInSeconds = 7 * 24 * 3600 // 一个星期多少秒
	scorePerVote     = 432           // 每一票值多少分
)

var (
	ErrVoteTimeExpire = errors.New("投票时间已过")
)

// CreatePost 记录新建帖子的时间
func CreatePost(postID int64) error {
	_, err := client.ZAdd(getRedisKey(KeyPostTimeZset), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: postID,
	}).Result()
	return err
}

func VoteForPost(userID, postID string, value float64) error {
	// 1、判断投票限制
	// 去redis取帖子的发帖时间
	postTime := client.ZScore(getRedisKey(KeyPostScoreZset), postID).Val()
	if float64(time.Now().Unix())-postTime > oneWeekInSeconds {
		return ErrVoteTimeExpire // 大于一个星期不给投票了
	}
	// 2、更新帖子分数
	// 先查当前用户给当前帖子之前的投票记录
	ov := client.ZScore(getRedisKey(KeyPostVotedZSetPF+postID), userID).Val()
	var op float64
	if value > ov {
		op = 1
	} else {
		op = -1
	}
	diff := math.Abs(ov - value) // 计算两次投票的差值
	_, err := client.ZIncrBy(getRedisKey(KeyPostScoreZset), op*diff*scorePerVote, postID).Result()
	if ErrVoteTimeExpire != nil {
		return err
	}
	// 3、记录用户为该帖子投票的数据
	if value == 0 {
		_, err = client.ZRem(getRedisKey(KeyPostVotedZSetPF+postID), userID).Result()
	} else {
		client.ZAdd(getRedisKey(KeyPostVotedZSetPF+postID), redis.Z{
			Score:  value, // 赞成票还是反对票
			Member: userID,
		}).Result()
	}
	return err
}
